home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_400
/
428_02
/
help
/
hc.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-03-13
|
9KB
|
361 lines
/*
** hc.c
**
** Help-Compiler, Help compiler utility.
** Compile with any memory model but large data (compact
** or large) provides more run-time memory.
**
** Pictor, Version 1.51, Copyright (c) 1992-94 SoftCircuits
** Redistributed by permission.
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <pictor.h>
#include <compress.h>
#define MAX_LABEL 80
struct item {
char label[MAX_LABEL + 1];
long offset;
unsigned comp_size;
unsigned uncomp_size;
struct item *next;
};
struct item *first = NULL;
struct item **array;
char signature[] = "PICTORHLP00";
unsigned num_topics,max_comp = 0,max_uncomp = 0;
unsigned comp_size,uncomp_size;
unsigned errors = 0,warnings = 0;
unsigned line = 0;
char *whtspc = " \t\n";
char buffer[BUFSIZ];
char *outfile;
#define WARN 0x00
#define ERROR 0x01
#define FATAL 0x02
/*
** displays diagnostic and counts error
*/
void error(char *msg,int type)
{
static char *error_types[] = {
"Warning",
"Error",
"Fatal error",
};
printf("%s : ",error_types[type]);
if(line != 0) printf("Line %d : ",line);
printf("%s\n",msg);
if(type == WARN)
warnings++;
else
errors++;
} /* error */
/*
** sets dos errorlevel to number of errors, closes all files and exits
** this function deletes the temporary file and if errors have occured,
** deletes the output file
*/
void terminate(void)
{
fcloseall();
if(errors) {
printf("\nOutput file not created\n");
unlink(outfile);
}
exit(errors);
} /* terminate */
/*
** compare routine for qsort()
*/
int compare(const void *elem1,const void *elem2)
{
return(stricmp(*(char **)elem1,*(char **)elem2));
} /* compare */
/*
** builds compressed output file from input file
*/
void create_output(char *filename,FILE *tmp_stream)
{
int len;
unsigned i;
FILE *stream;
NODE *root_node;
struct item *curr;
void *inbuff,*outbuff;
long fpos = 0,fpos2 = 0;
/* compute most efficient compression code tree */
rewind(tmp_stream);
root_node = gettree(tmp_stream);
if(root_node == NULL) {
error("Insufficient memory",FATAL);
terminate();
}
/* open output file */
stream = fopen(filename,"wb");
if(stream == NULL) {
error("Unable to create output file",FATAL);
terminate();
}
/* write signature */
fwrite(signature,sizeof(char),sizeof(signature),stream);
/* write code tree */
len = writetree(root_node,(BYTE *)buffer);
putw(len,stream);
fwrite(buffer,sizeof(char),len,stream);
/* make room for file offset pointer */
fpos = ftell(stream);
fwrite(&fpos,sizeof(long),1,stream);
/* allocate compression buffers */
inbuff = malloc(max_uncomp);
outbuff = malloc(max_uncomp + 512);
if(inbuff == NULL || outbuff == NULL) {
error("Insufficient memory",FATAL);
terminate();
}
/* write compressed help text */
rewind(tmp_stream);
for(i = 0,curr = first;curr != NULL;i++,curr = curr->next) {
fread(inbuff,sizeof(char),curr->uncomp_size,tmp_stream);
curr->comp_size = compress(inbuff,curr->uncomp_size,outbuff,root_node);
if(curr->comp_size > max_comp)
max_comp = curr->comp_size;
curr->offset = ftell(stream);
putw(curr->comp_size,stream);
putw(curr->uncomp_size,stream);
fwrite(outbuff,sizeof(char),curr->comp_size,stream);
}
fpos2 = ftell(stream);
/* */
putw(num_topics,stream);
putw(max_comp,stream);
putw(max_uncomp,stream);
/* write sorted file offsets for each topics */
for(i = 0;i < num_topics;i++) {
fwrite(&(array[i]->offset),sizeof(array[0]->offset),1,stream);
}
/* */
inbuff = realloc(inbuff,uncomp_size);
outbuff = realloc(outbuff,uncomp_size + 512);
if(inbuff == NULL || outbuff == NULL) {
error("Insufficient memory",FATAL);
terminate();
}
/* */
fread(inbuff,sizeof(char),uncomp_size,tmp_stream);
/* compress topic labels */
comp_size = compress(inbuff,uncomp_size,outbuff,root_node);
/* */
putw(comp_size,stream);
putw(uncomp_size,stream);
/* write compressed topic labels to output file */
fwrite(outbuff,sizeof(char),comp_size,stream);
/* */
fseek(stream,fpos,SEEK_SET);
fwrite(&fpos2,sizeof(fpos2),1,stream);
fclose(tmp_stream);
fclose(stream);
} /* create_output */
/*
** parses the input file
** returns a pointer to the temporary file stream
*/
FILE *read_input(char *filename)
{
FILE *stream,*tmp_stream;
struct item *new,*curr = NULL;
int in_topic = FALSE;
char *cptr;
/* open input file */
if((stream = fopen(filename,"rt")) == NULL) {
error("Unable to open input file",FATAL);
terminate();
}
/* create temporary file */
if((tmp_stream = tmpfile()) == NULL) {
error("Unable to create temporary file",FATAL);
terminate();
}
for(line = 1;fgets(buffer,BUFSIZ,stream);line++) {
/* find first non-space character */
cptr = (buffer + strspn(buffer,whtspc));
if(*cptr == '@') { /* compiler directive */
cptr = strtok(cptr + 1,whtspc);
if(cptr == NULL) {
error("Compiler directive expected following '@'",ERROR);
}
else if(!strcmpi(cptr,"BEGIN")) { /* new topic */
if(!in_topic) {
if((new = malloc(sizeof(struct item))) == NULL) {
error("Insufficient memory",FATAL);
terminate();
}
if(first == NULL)
first = new;
else
curr->next = new;
curr = new;
curr->next = NULL;
curr->label[0] = '\0';
curr->uncomp_size = 0;
cptr = strtok(NULL,"");
if(cptr == NULL || *(cptr += strspn(cptr,whtspc)) == '\0') {
error("@BEGIN must be followed by topic label",ERROR);
}
else {
/* strip trailing whitespace */
while(isspace(cptr[strlen(cptr) - 1]))
cptr[strlen(cptr) - 1] = '\0';
if(strlen(cptr) > MAX_LABEL) {
error("Topic label too long, truncating",WARN);
cptr[MAX_LABEL] = '\0';
}
strcpy(curr->label,cptr);
/* search for duplicate labels */
for(new = first;new->next != NULL;new = new->next) {
if(!stricmp(cptr,new->label)) {
error("Topic already defined",ERROR);
break;
}
}
}
in_topic = TRUE;
}
else error("@BEGIN before @END",ERROR);
}
else if(!strcmpi(cptr,"END")) {
if(in_topic) {
if(curr->uncomp_size > max_uncomp)
max_uncomp = curr->uncomp_size;
num_topics++;
in_topic = FALSE;
if(strtok(NULL,whtspc) != NULL)
error("Extra characters ignored",WARN);
}
else error("@END before @BEGIN",ERROR);
}
else error("Unknown compiler directive",ERROR);
}
else {
if(in_topic) {
fwrite(buffer,sizeof(char),strlen(buffer),tmp_stream);
curr->uncomp_size += strlen(buffer);
}
else if(*cptr != '\0' && *cptr != ';')
error("Text outside @BEGIN/@END",ERROR);
}
}
if(ferror(stream)) {
error("Error reading input file",FATAL);
terminate();
}
else if(in_topic) {
error("Unexpected end-of-file",ERROR);
if(curr->uncomp_size > max_uncomp)
max_uncomp = curr->uncomp_size;
num_topics++;
}
fclose(stream);
/* indicate we're no longer processing input file */
line = 0;
return(tmp_stream);
} /* read_input */
/*
** here's main()
*/
void main(int argc,char *argv[])
{
unsigned i,len;
FILE *tmp_stream;
struct item *curr;
printf("HC - Help Compiler, Version 1.51,"
" Copyright (c) 1992-94 SoftCircuits\n");
printf("Redistributed by permission.\n\n");
if(argc != 3) {
printf("Usage: HC <input-file> <output-file>\n");
terminate();
}
outfile = argv[2];
/* process input file */
tmp_stream = read_input(argv[1]);
if(num_topics == 0) {
error("Input file contains no help topics",FATAL);
terminate();
}
/* build array and sort array of pointers to items */
if((array = malloc(sizeof(struct item *) * num_topics)) == NULL) {
error("Insufficient memory",FATAL);
terminate();
}
for(i = 0,curr = first;curr != NULL;i++,curr = curr->next) {
array[i] = curr;
}
qsort(array,num_topics,sizeof(struct item *),compare);
/* write so